package com.atguigu.tingshu.search.service.impl;

import co.elastic.clients.elasticsearch.core.search.*;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.util.PinYinUtils;
import com.atguigu.tingshu.model.base.BaseEntity;
import com.atguigu.tingshu.search.repository.SuggestIndexRepository;

import com.atguigu.tingshu.vo.album.AlbumStatVoMsg;
import org.redisson.api.RBloomFilter;
import org.redisson.api.RedissonClient;
import org.springframework.data.elasticsearch.core.suggest.Completion;

import co.elastic.clients.elasticsearch._types.aggregations.*;
import co.elastic.clients.json.JsonData;

import cn.hutool.core.util.PageUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldSort;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch._types.SortOptions;
import co.elastic.clients.elasticsearch._types.SortOrder;
import co.elastic.clients.elasticsearch._types.query_dsl.*;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.alibaba.fastjson.JSON;
import com.atguigu.tingshu.album.client.AlbumInfoFeignClient;
import com.atguigu.tingshu.album.client.CategoryFeignClient;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.BaseCategory3;
import com.atguigu.tingshu.model.album.BaseCategoryView;
import com.atguigu.tingshu.model.search.AttributeValueIndex;
import com.atguigu.tingshu.model.search.SuggestIndex;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.search.AlbumIndexQuery;
import com.atguigu.tingshu.search.repository.AlbumIndexRepository;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexSearchVo;
import com.atguigu.tingshu.vo.search.AlbumInfoIndexVo;
import com.atguigu.tingshu.vo.search.AlbumSearchResponseVo;

import com.atguigu.tingshu.model.search.AlbumInfoIndex;
import com.atguigu.tingshu.search.service.SearchService;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
import java.util.stream.Stream;


@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class SearchServiceImpl implements SearchService {

    @Autowired
    private SuggestIndexRepository suggestIndexRepository;

    @Autowired
    private AlbumIndexRepository albumIndexRepository;

    @Autowired
    private AlbumInfoFeignClient albumInfoFeignClient;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private ElasticsearchClient elasticsearchClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    @SneakyThrows
    @Override
    public List<String> completeSuggest(String keyword) {

        //创建suggester对象
        Suggester suggester = new Suggester.Builder()
                //添加suggester
                .suggesters("suggestionKeyword", new FieldSuggester.Builder().prefix(keyword).completion(new CompletionSuggester.Builder()
                        // 设置字段
                        .field("keyword")
                        // 设置是否去重
                        .skipDuplicates(true)
                        // 设置返回数量
                        .size(10)
                        // 设置模糊匹配
                        .fuzzy(new SuggestFuzziness.Builder().fuzziness("AUTO").build())
                        .build()).build())
                .suggesters("suggestionkeywordPinyin", new FieldSuggester.Builder().prefix(keyword).completion(new CompletionSuggester.Builder()
                        .field("keywordPinyin")
                        .skipDuplicates(true)
                        .size(10)
                        .fuzzy(new SuggestFuzziness.Builder().fuzziness("AUTO").build())
                        .build()).build())
                .suggesters("suggestionkeywordSequence", new FieldSuggester.Builder().prefix(keyword).completion(new CompletionSuggester.Builder()
                        .field("keywordSequence")
                        .skipDuplicates(true)
                        .size(10)
                        .fuzzy(new SuggestFuzziness.Builder().fuzziness("AUTO").build())
                        .build()).build())
                .build();
        //拼接查询条件 创建searchRequest对象
        SearchRequest searchRequest = new SearchRequest.Builder()
                .index("suggestinfo")
                .suggest(suggester)
                .build();
        //执行查询
        SearchResponse<SuggestIndex> searchResponse = elasticsearchClient.search(searchRequest, SuggestIndex.class);
        List<String> suggestionKeyword = parseSuggestResult(searchResponse, "suggestionKeyword");
        List<String> suggestionkeywordSequence = parseSuggestResult(searchResponse, "suggestionkeywordSequence");
        List<String> suggestionkeywordPinyin = parseSuggestResult(searchResponse, "suggestionkeywordPinyin");
        log.info(searchResponse.toString());
        return Stream
                .of(suggestionKeyword, suggestionkeywordSequence, suggestionkeywordPinyin)
                .flatMap(List::stream)
                .collect(Collectors.toList());
    }



    @SneakyThrows
    @Override
    public void updateLatelyAlbumRanking() {
        //创建query对象
        Query query = new Query.Builder().matchAll(QueryBuilders.matchAll().build()).build();
        //创建Aggregation.Builder.ContainerBuilder对象
        Aggregation.Builder.ContainerBuilder containerBuilder = new Aggregation.Builder().terms(builder -> builder.field("category1Id").size(100));

        // 定义统计维度
        String[] rankingDimensionArray = new String[]{"hotScore", "playStatNum", "subscribeStatNum", "buyStatNum", "commentStatNum"};
        for (String ranking : rankingDimensionArray) {

            SortOptions sortOptions = new SortOptions.Builder().field(builder -> builder.field(ranking).order(SortOrder.Desc)).build();
            Aggregation aggregation = new Aggregation.Builder().topHits(builder -> builder.size(10).sort(sortOptions)).build();
            containerBuilder.aggregations(ranking + "Agg", aggregation);
        }


        //1.获取searchRequest对象
        SearchRequest searchRequest = new SearchRequest.Builder()
                .index("albuminfo")
                .query(query)
                .source(new SourceConfig.Builder().fetch(false).build())
                .aggregations("category1IdAgg", containerBuilder.build())
                .build();

        //2.执行查询
        SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);
        //解析数据
        Aggregate aggregate = searchResponse.aggregations().get("category1IdAgg");
        LongTermsAggregate longTermsAggregate = (LongTermsAggregate) aggregate._get();
        List<LongTermsBucket> array = longTermsAggregate.buckets().array();
        for (LongTermsBucket longTermsBucket : array) {
            Long category1Id = longTermsBucket.key();
            for (String ranking : rankingDimensionArray) {
                TopHitsAggregate topHitsAggregate = (TopHitsAggregate) longTermsBucket.aggregations().get(ranking + "Agg")._get();
                List<Hit<JsonData>> hits = topHitsAggregate.hits().hits();
                List<AlbumInfoIndex> albumInfoIndexList = hits.stream().map(hit -> {
                    AlbumInfoIndex albumInfoIndex = hit.source().to(AlbumInfoIndex.class);
                    return albumInfoIndex;
                }).collect(Collectors.toList());

                //存储到redis中
                String redisKey = RedisConstant.RANKING_KEY_PREFIX + category1Id;
                stringRedisTemplate.opsForHash().put(redisKey, ranking, JSON.toJSONString(albumInfoIndexList));
            }

        }

    }

    @Override
    public List<AlbumInfoIndexVo> findRankingList(Long category1Id, String dimension) {
        String redisKey = RedisConstant.RANKING_KEY_PREFIX + category1Id;
        String obj = stringRedisTemplate.opsForHash().get(redisKey, dimension).toString();
        if (obj != null) {
            List<AlbumInfoIndexVo> albumInfoIndexVoList = JSON.parseArray(obj, AlbumInfoIndexVo.class);
            return albumInfoIndexVoList;
        }
        return null;
    }

    @Override
    public void updateAlbumStat(AlbumStatVoMsg albumStatVoMsg) {
        Long albumId = albumStatVoMsg.getAlbumId();
        AlbumInfoIndex albumInfoIndex = albumIndexRepository.findById(albumId).get();
        switch (albumStatVoMsg.getStatType()){
            case SystemConstant.ALBUM_STAT_PLAY -> albumInfoIndex.setPlayStatNum(albumStatVoMsg.getStatNum());
            case SystemConstant.ALBUM_STAT_SUBSCRIBE -> albumInfoIndex.setSubscribeStatNum(albumStatVoMsg.getStatNum());
            case SystemConstant.ALBUM_STAT_BROWSE -> albumInfoIndex.setBuyStatNum(albumStatVoMsg.getStatNum());
            case SystemConstant.ALBUM_STAT_COMMENT -> albumInfoIndex.setCommentStatNum(albumStatVoMsg.getStatNum());
        }
        albumIndexRepository.save(albumInfoIndex);
    }

    private List<String> parseSuggestResult(SearchResponse<SuggestIndex> searchResponse, String suggesterName) {
//        Map<String, List<Suggestion<SuggestIndex>>> suggest =
        //解析数据并返回
        return searchResponse
                .suggest()
                .get(suggesterName)
                .get(0)
                .completion()
                .options()
                .stream()
                .map(CompletionSuggestOption::source)
                .filter(Objects::nonNull)
                .map(SuggestIndex::getTitle)
                .collect(Collectors.toList());

    }

    @SneakyThrows
    @Override
    public List<AlbumInfoIndexSearchVo> channel(Long category1Id) {
        List<BaseCategory3> baseCategory3Id = categoryFeignClient.findTopBaseCategory3(category1Id).getData();
        Map<Long, BaseCategory3> baseCategory3Map = baseCategory3Id.stream().collect(Collectors.toMap(BaseEntity::getId, baseCategory3 -> baseCategory3));
        Set<Long> c3Ids = baseCategory3Map.keySet();
        //拼接查询条件
        SearchRequest searchRequest = queryConditions(c3Ids, category1Id);
        SearchResponse<AlbumInfoIndexSearchVo> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndexSearchVo.class);
        //解析数据并返回
        return analysisSearchResponse(searchResponse, baseCategory3Map);
    }

    private List<AlbumInfoIndexSearchVo> analysisSearchResponse(SearchResponse<AlbumInfoIndexSearchVo> searchResponse, Map<Long, BaseCategory3> baseCategory3Map) {
        //解析searchResponse获取专辑分类Map
        Map<String, Aggregate> aggregations = searchResponse.aggregations();
        //通过字段获取聚合数据
        Aggregate aggregate = aggregations.get("category3IdAgg");
        LongTermsAggregate longTermsAggregate = (LongTermsAggregate) aggregate._get();
        List<LongTermsBucket> bucketList = longTermsAggregate.buckets().array();
        List<AlbumInfoIndexSearchVo> list = new ArrayList<>();
        //遍历bucketList
        for (LongTermsBucket longTermsBucket : bucketList) {
            //获取分类id
            long key = longTermsBucket.key();
            //获取三级分类下的对应的专辑数据
            Map<String, Aggregate> aggregation = longTermsBucket.aggregations();
            //通过字段获取专辑数据
            Aggregate score = aggregation.get("topAlbumInfoAgg");
            TopHitsAggregate topHitsAggregate = (TopHitsAggregate) score._get();
            List<Hit<JsonData>> hits = topHitsAggregate.hits().hits();
            List<AlbumInfoIndex> collect = hits.stream().map(hit -> {
                //获取专辑数据
                assert hit.source() != null;
                return hit.source().to(AlbumInfoIndex.class);

            }).collect(Collectors.toList());
            AlbumInfoIndexSearchVo albumInfoIndexSearchVo = new AlbumInfoIndexSearchVo();
            albumInfoIndexSearchVo.setBaseCategory3(baseCategory3Map.get(key));
            albumInfoIndexSearchVo.setList(collect);
            list.add(albumInfoIndexSearchVo);
        }

        return list;
    }

    private SearchRequest queryConditions(Set<Long> c3Ids, Long category1Id) {


        //创建FieldValue对象 构建三级分类的搜索参数
        List<FieldValue> fieldValueList = c3Ids.stream().map(c3Id -> {
            return new FieldValue.Builder()
                    .longValue(c3Id)
                    .build();
        }).collect(Collectors.toList());

        //创建TermsQueryField对象
        TermsQueryField termsQueryField = new TermsQueryField.Builder()
                .value(fieldValueList)
                .build();

        //创建BoolQuery对象
        BoolQuery boolQuery = new BoolQuery.Builder()
                .must(builder -> builder.term(QueryBuilders.term().field("category1Id").value(category1Id).build()))
                .must(builder -> builder.terms(QueryBuilders.terms().field("category3Id").terms(termsQueryField).build()))
                .build();

        //创建query对象
        Query query = new Query.Builder()
                .bool(boolQuery)
                .build();

        //构建SourceConfig对象
        SourceConfig sourceConfig = new SourceConfig.Builder()
                .fetch(false)
                .build();
        //创建一个聚合的Aggregation对象
        SortOptions sortOptions = new SortOptions.Builder().field(builder -> builder.field("hotScore").order(SortOrder.Desc)).build();
        Aggregation aggregations = new Aggregation.Builder().topHits(builder -> builder.size(6).sort(sortOptions)).build();
        //构建Aggregation对象
        Aggregation aggregation = new Aggregation.Builder()
                .terms(builder -> builder.field("category3Id").size(100))
                .aggregations("topAlbumInfoAgg", aggregations)
                .build();
        SearchRequest searchRequest = new SearchRequest.Builder()
                .index("albuminfo")
                .query(query)
                .source(sourceConfig)
                .aggregations("category3IdAgg", aggregation)
                .build();
        log.info("searchRequest:{}", searchRequest);
        return searchRequest;
    }

    @Override
    public void upperAlbum(Long albumId) {
        //构建AlbumInfoIndex对象
        AlbumInfoIndex albumInfoIndex = new AlbumInfoIndex();
        CompletableFuture<AlbumInfo> cf1 = CompletableFuture.supplyAsync(() -> {
            //获取AlbumInfo
            Result<AlbumInfo> albumInfoResult = albumInfoFeignClient.getAlbumInfo(albumId);
            AlbumInfo albumInfo = albumInfoResult.getData();
            //复制数据
            BeanUtils.copyProperties(albumInfo, albumInfoIndex);
            //专辑是否完结
            albumInfoIndex.setIsFinished(String.valueOf(albumInfo.getIsFinished()));
            //专辑属性值集合
            List<AlbumAttributeValue> albumAttributeValueVoList = albumInfo.getAlbumAttributeValueVoList();
            //通过stream流遍历专辑属性值集合
            List<AttributeValueIndex> list = albumAttributeValueVoList.stream().map(albumAttributeValue -> {
                //构建AttributeValueIndex对象
                AttributeValueIndex attributeValueIndex = new AttributeValueIndex();
                attributeValueIndex.setAttributeId(albumAttributeValue.getAttributeId());
                attributeValueIndex.setValueId(albumAttributeValue.getValueId());
                //返回attributeValueIndex对象
                return attributeValueIndex;
            }).collect(Collectors.toList());
            //专辑属性值集合
            albumInfoIndex.setAttributeValueIndexList(list);
            return albumInfo;
        });
        //请求专辑微服务根据三级分类id查询专辑信息
        CompletableFuture<Void> cf2 = cf1.thenAcceptAsync(albumInfo -> {
            Result<BaseCategoryView> viewResult = categoryFeignClient.findCategoryInfoByC3Id(albumInfo.getCategory3Id());
            albumInfoIndex.setCategory1Id(viewResult.getData().getCategory1Id());
            albumInfoIndex.setCategory2Id(viewResult.getData().getCategory2Id());
            albumInfoIndex.setCategory3Id(viewResult.getData().getCategory3Id());
        });
        CompletableFuture<Void> cf3 = cf1.thenAcceptAsync(albumInfo -> {
            Result<UserInfo> userInfo = userInfoFeignClient.getUserInfoById(albumInfo.getUserId());
            //专辑作者的名字
            albumInfoIndex.setAnnouncerName(userInfo.getData().getNickname());
        });

        CompletableFuture<Void> cf4 = CompletableFuture.runAsync(() -> {
            AlbumStatVo albumStatVo = albumInfoFeignClient.getAlbumStatVo(albumId).getData();
            Integer playStatNum = albumStatVo.getPlayStatNum();
            Integer subscribeStatNum = albumStatVo.getSubscribeStatNum();
            Integer buyStatNum = albumStatVo.getBuyStatNum();
            Integer commentStatNum = albumStatVo.getCommentStatNum();
            //播放量
            albumInfoIndex.setPlayStatNum(playStatNum);
            //订阅量
            albumInfoIndex.setSubscribeStatNum(subscribeStatNum);
            //购买量
            albumInfoIndex.setBuyStatNum(buyStatNum);
            //评论数
            albumInfoIndex.setCommentStatNum(commentStatNum);
            //商品的热度
            albumInfoIndex.setHotScore(playStatNum * 1.0 + subscribeStatNum * 2.0 + buyStatNum * 3.0 + commentStatNum * 4.0);

        });
        CompletableFuture.allOf(cf1, cf2, cf3, cf4).join();
        log.info(JSON.toJSONString(albumInfoIndex));
        //将数据保存到es中
        albumIndexRepository.save(albumInfoIndex);
        //初始化题词库
        CompletableFuture.runAsync(() -> {
            initSuggestinfo(albumInfoIndex);
        });
        //把当前专辑的id存入到布隆过滤器中
        RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER);
        bloomFilter.add(albumId);
        log.info("向布隆过滤器中存储了数据:{}", albumId);
    }

    private void initSuggestinfo(AlbumInfoIndex albumInfoIndex) {
        //保存专辑标题数据到suggestinfo索引库中
        SuggestIndex titleSuggestIndex = new SuggestIndex();
        String title = albumInfoIndex.getAlbumTitle();
        titleSuggestIndex.setId(UUID.randomUUID().toString().replace("-", ""));
        titleSuggestIndex.setTitle(title);
        titleSuggestIndex.setKeyword(new Completion(new String[]{title}));
        titleSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(title)}));
        titleSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(title)}));
        suggestIndexRepository.save(titleSuggestIndex);
        //保存专辑简介数据到suggestinfo索引库中
        SuggestIndex albumIntroSuggestIndex = new SuggestIndex();
        String albumIntro = albumInfoIndex.getAlbumIntro();
        albumIntroSuggestIndex.setId(UUID.randomUUID().toString().replace("-", ""));
        albumIntroSuggestIndex.setTitle(albumIntro);
        albumIntroSuggestIndex.setKeyword(new Completion(new String[]{albumIntro}));
        albumIntroSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(albumIntro)}));
        albumIntroSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(albumIntro)}));
        suggestIndexRepository.save(albumIntroSuggestIndex);
        //保存专辑作者名字数据到suggestinfo索引库中
        SuggestIndex nameSuggestIndex = new SuggestIndex();
        String announcerName = albumInfoIndex.getAnnouncerName();
        nameSuggestIndex.setId(UUID.randomUUID().toString().replace("-", ""));
        nameSuggestIndex.setTitle(announcerName);
        nameSuggestIndex.setKeyword(new Completion(new String[]{announcerName}));
        nameSuggestIndex.setKeywordPinyin(new Completion(new String[]{PinYinUtils.toHanyuPinyin(announcerName)}));
        nameSuggestIndex.setKeywordSequence(new Completion(new String[]{PinYinUtils.getFirstLetter(announcerName)}));
        suggestIndexRepository.save(nameSuggestIndex);
    }


    @Override
    public void lowerAlbum(Long albumId) {
        albumIndexRepository.deleteById(albumId);
        //创建一个新的布隆过滤器
        RBloomFilter<Long> bloomFilter = redissonClient.getBloomFilter(RedisConstant.ALBUM_BLOOM_FILTER_NEW);
        bloomFilter.tryInit(100000000, 0.0000001);
        albumIndexRepository.findAll().forEach(albumInfoIndex ->{
            bloomFilter.add(albumInfoIndex.getId());
        } );

        log.info("新的布隆过滤器新建成功");
        String script = "redis.call(\"del\",KEYS[1])\n" +
                "redis.call(\"del\",\"{\" .. KEYS[1] .. \"} : config\" )\n" +
                "redis.call(\"rename\",KEYS[2] ,KEYS[1])\n" +
                "redis.call(\"rename\",\"{\" .. KEYS[2] .. \"} : config\" ,\"{\" .. KEYS[1] .. \"} : config\")\n" +
                "return 1;";

        Long execute = stringRedisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class), Arrays.asList(RedisConstant.ALBUM_BLOOM_FILTER, RedisConstant.ALBUM_BLOOM_FILTER_NEW));
        if (execute.equals(1)) {
            log.info("旧的布隆过滤器删除成功");
        }

    }

    @SneakyThrows
    @Override
    public AlbumSearchResponseVo search(AlbumIndexQuery albumIndexQuery) {
        //构建查询条件
        SearchRequest searchRequest = this.buildSearchRequest(albumIndexQuery);
        //执行查询
        SearchResponse<AlbumInfoIndex> searchResponse = elasticsearchClient.search(searchRequest, AlbumInfoIndex.class);

        return parseSearchResult(searchResponse, albumIndexQuery);
    }


    private AlbumSearchResponseVo parseSearchResult(SearchResponse<AlbumInfoIndex> searchResponse, AlbumIndexQuery albumIndexQuery) {
        //封装响应结果
        AlbumSearchResponseVo albumSearchResponseVo = new AlbumSearchResponseVo();
        HitsMetadata<AlbumInfoIndex> hitsMetadata = searchResponse.hits();

        List<Hit<AlbumInfoIndex>> hitList = hitsMetadata.hits();
        //通过stream流遍历hitList 通过lambda表达式获取数据
        List<AlbumInfoIndexVo> albumInfoIndexVos = hitList.stream().map(hit -> {
            //获取到AlbumInfoIndex对象
            AlbumInfoIndex albumInfoIndex = hit.source();
            //封装响应结果
            AlbumInfoIndexVo albumInfoIndexVo = new AlbumInfoIndexVo();
            assert albumInfoIndex != null;
            BeanUtils.copyProperties(albumInfoIndex, albumInfoIndexVo);
            //获取高亮数据
            Map<String, List<String>> highlight = hit.highlight();
            if (!CollectionUtils.isEmpty(highlight)) {
                List<String> albumTitle = highlight.get("albumTitle");
                if (!CollectionUtils.isEmpty(albumTitle)) {
                    //封装高亮数据 重新为AlbumTitle赋值
                    albumInfoIndexVo.setAlbumTitle(albumTitle.get(0));
                }
            }
            return albumInfoIndexVo;
        }).collect(Collectors.toList());

        //封装商品数据
        albumSearchResponseVo.setList(albumInfoIndexVos);
        assert hitsMetadata.total() != null;
        //满足条件的总记录数
        long total = hitsMetadata.total().value();
        albumSearchResponseVo.setTotal(total);
        albumSearchResponseVo.setPageSize(albumIndexQuery.getPageSize());
        albumSearchResponseVo.setPageNo(albumIndexQuery.getPageNo());
        //计算页码数
        int totalPage = PageUtil.totalPage(total, albumIndexQuery.getPageSize());
        albumSearchResponseVo.setTotalPages(Long.parseLong(String.valueOf(totalPage)));

        return albumSearchResponseVo;
    }

    private SearchRequest buildSearchRequest(AlbumIndexQuery albumIndexQuery) {
        //创建一个boolBuilder对象
        BoolQuery.Builder boolBuilder = new BoolQuery.Builder();
        //关键字搜索 模糊搜索
        String keyword = albumIndexQuery.getKeyword();
        if (!StringUtils.isEmpty(keyword)) {
            boolBuilder.must(builder -> builder.multiMatch(QueryBuilders.multiMatch().fields("albumTitle").query(keyword).build()));
        } else {
            boolBuilder.must(builder -> builder.matchAll(QueryBuilders.matchAll().build()));
        }

        //拼接分类查询 精确查询
        Long category1Id = albumIndexQuery.getCategory1Id();
        if (category1Id != null) {
            boolBuilder.must(builder -> builder.term(QueryBuilders.term().field("category1Id").value(category1Id).build()));
        }
        Long category2Id = albumIndexQuery.getCategory2Id();
        if (category2Id != null) {
            boolBuilder.must(builder -> builder.term(QueryBuilders.term().field("category2Id").value(category2Id).build()));
        }
        Long category3Id = albumIndexQuery.getCategory3Id();
        if (category3Id != null) {
            boolBuilder.must(builder -> builder.term(QueryBuilders.term().field("category3Id").value(category3Id).build()));
        }

        //根据属性Id检索 请求参数格式：属性Id:属性值Id
        List<String> attributeList = albumIndexQuery.getAttributeList();
        if (!CollectionUtils.isEmpty(attributeList)) {
            for (String attrInfoValue : attributeList) {
                String[] split = attrInfoValue.split(":");
                String attrId = split[0];
                String valueId = split[1];

                //创建boolQuery对象
                BoolQuery boolQuery = new BoolQuery.Builder()
                        .must(builder -> builder.term(QueryBuilders.term().field("attributeValueIndexList.attributeId").value(attrId).build()))
                        .must(builder -> builder.term(QueryBuilders.term().field("attributeValueIndexList.valueId").value(valueId).build()))
                        .build();
                //创建query对象
                Query query = new Query.Builder()
                        .bool(boolQuery)
                        .build();
                //创建nestedQuery对象
                NestedQuery nestedQuery = new NestedQuery.Builder()
                        .path("attributeValueIndexList")
                        .query(query)
                        .build();
                boolBuilder.must(builder -> builder.nested(nestedQuery));
            }
        }

        //创建query对象
        Query query = new Query.Builder()
                .bool(boolBuilder.build())
                .build();

        String order = albumIndexQuery.getOrder();
        //排序字段拼接
        FieldSort fieldSort = null;
        if (!StringUtils.isEmpty(order)) {
            String[] split = order.split(":");
            String orderInfo = split[0];
            String orderSort = split[1];
            SortOrder sortOrder = "desc".equalsIgnoreCase(orderSort) ? SortOrder.Desc : SortOrder.Asc;
            switch (orderInfo) {
                case "1" -> fieldSort = new FieldSort.Builder().field("hotScore").order(sortOrder).build();
                case "2" -> fieldSort = new FieldSort.Builder().field("playStatNum").order(sortOrder).build();
                case "3" -> fieldSort = new FieldSort.Builder().field("createTime").order(sortOrder).build();
            }

        } else {
            fieldSort = new FieldSort.Builder()
                    .field("hotScore")
                    .order(SortOrder.Desc)
                    .build();
        }

        //创建SortOptions对象
        SortOptions sortOptions = new SortOptions.Builder()
                .field(fieldSort)
                .build();

        Integer from = (albumIndexQuery.getPageNo() - 1) * albumIndexQuery.getPageSize();
        Integer size = albumIndexQuery.getPageSize();
        //创建searchRequest对象
        SearchRequest.Builder builder = new SearchRequest.Builder();
        builder.query(query)
                .sort(sortOptions)
                .from(from)
                .size(size);

        if (!StringUtils.isEmpty(keyword)) {
            //查询条件中的高亮
            Highlight highlight = new Highlight.Builder()
                    .fields("albumTitle", highlightBuilder -> highlightBuilder.preTags("<font color='red'>").postTags("</font>"))
                    .build();

            builder.highlight(highlight);
        }
        //创建searchRequest对象
        SearchRequest searchRequest = builder.build();

        log.info(searchRequest.toString());
        //返回searchRequest对象
        return searchRequest;
    }


}
